package com.inmaytide.website.service.system.impl;

import com.inmaytide.website.domain.entities.system.SysLog;
import com.inmaytide.website.domain.entities.system.SysUser;
import com.inmaytide.website.mapper.system.SysLogMapper;
import com.inmaytide.website.service.system.SysLogService;
import com.inmaytide.website.utils.CommonUtils;
import com.inmaytide.website.utils.DateUtils;
import com.inmaytide.website.utils.configurations.SystemConstants;
import com.inmaytide.website.utils.log.annotation.LogInformation;
import com.inmaytide.website.utils.office.ExcelUtils;
import com.inmaytide.website.utils.pagination.Pagination;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

/**
 * @author luomiao
 * @since May 20, 2016
 */
@Service
@Transactional(readOnly = true)
public class SysLogServiceImpl implements SysLogService {

    @Resource
    private SysLogMapper mapper;

    @Override
    @Transactional
    public void insert(SysLog inst) {
        if (ObjectUtils.isEmpty(inst.getOperator())) {
            inst.setOperator(getOperator());
        }
        if (StringUtils.isEmpty(inst.getOperatingTime())) {
            inst.setOperatingTime(DateUtils.getDatetimeStr());
        }
        if (StringUtils.isEmpty(inst.getOperatorIp())) {
            inst.setOperatorIp(CommonUtils.getCurrentSession().getHost());
        }
        mapper.insert(inst);
    }

    @Override
    @Transactional
    public void deleteBatch(Integer... ids) {
        Arrays.stream(ids).forEach(id -> mapper.deleteByPrimaryKey(id));
    }

    @Override
    @Transactional
    public void deleteBatch() {
        mapper.clear();
    }

    @Override
    @Transactional
    public void delete(Integer id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    @Transactional
    public void insert(LogInformation annotation, String methodName) {
        SysLog inst = new SysLog();
        inst.setDescription(getDescription(annotation, methodName));
        inst.setResult(annotation.success());
        insert(inst);
    }

    @Override
    @Transactional
    public void insert(LogInformation annotation, Throwable e, String methodName) {
        SysLog inst = new SysLog();
        inst.setDescription(getDescription(annotation, methodName));
        if (SystemConstants.LOG_DEFAULT_FAILURE_MESSAGE.equals(annotation.failure())) {
            inst.setResult(new StringBuilder("failure by: ").append(e.getMessage()).toString());
        } else {
            inst.setResult(annotation.failure());
        }
        insert(inst);
    }

    private Long getOperator() {
        SysUser user = CommonUtils.getCurrentUser();
        return ObjectUtils.isEmpty(user) ? -1 : user.getId();
    }

    private String getDescription(LogInformation annotation, String methodName) {
        return StringUtils.defaultIfEmpty(annotation.description(), methodName);
    }

    @Override
    public Pagination<SysLog> findList(HttpServletRequest request, Pagination<SysLog> pagination) {
        pagination.setConditions(createConditions(request));
        pagination.setCount(mapper.findCountByMultipleConditions(pagination));
        pagination.setResult(mapper.findListByMultipleConditionsAndPagination(pagination));
        return pagination;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void export(String type, Pagination<SysLog> pagination, OutputStream os) throws IOException {
        List<SysLog> logs;
        switch (type) {
            case "all":
                logs = mapper.findListByMultipleConditions(new HashMap<String, String>());
                break;
            case "current-page":
                logs = mapper.findListByMultipleConditionsAndPagination(pagination);
                break;
            case "current-conditions":
                logs = mapper.findListByMultipleConditions((Map<String, String>) pagination.getConditions());
                break;
            default:
                logs = new ArrayList<>();
        }
        new ExcelUtils(SysLog.class).write(os, logs);
    }

}